﻿/******************************************************************************
 * This file is part of libemb.
 *
 * libemb is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * libemb is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with libemb.  If not, see <http://www.gnu.org/licenses/>.
 *
 * Project: Embedme
 * Author : FergusZeng
 * Email  : cblock@126.com
 * git	  : https://git.oschina.net/cblock/embedme
 * Copyright 2014~2017 @ ShenZhen ,China
*******************************************************************************/
#include "Timer.h"
#include "Tracer.h"
#include <sys/select.h>
#include <sys/time.h>
#include <sys/types.h>
#include <unistd.h>

#define     TIMER_TICK_MS			100       /* 100ms */

Timer::Timer(RtcTime_S absTime)
{
	m_absTime = absTime;
	m_isExpired = false;
	m_isAbsTimer = true;
}
Timer::Timer(int interval, int unit)
{
	m_interval = interval;
	m_unit = unit;
	m_isExpired = false;
	m_isAbsTimer = false;
}

/**
 *  \brief  毫秒延时函数
 *  \param  ms 要延时的毫秒数
 *  \return void
 *  \note   none
 */
void Timer::msDelay(int ms)
{
	/* 一般情况下不需要十分精确的定时,所以这里利用select超时机制来定时 */
	struct timeval tv;
    if (ms<1000)
    {
	    tv.tv_sec = 0;
	    tv.tv_usec = ms*1000;
    }
    else
    {
        tv.tv_sec = ms/1000;
	    tv.tv_usec = (ms%1000)*1000;    
    }
	select(0,NULL,NULL,NULL,&tv);
}

Timer::~Timer()
{
	m_isExpired = true;
}

/* 复位定时器 */
int Timer::reset()
{
	if(m_isAbsTimer)
	{	
		m_absTime = m_absTime;
	}
	else
	{
		switch(m_unit)
		{
			case TIME_UNIT_MILLISECOND:
				m_timerMS = m_interval;
				break;
			case TIME_UNIT_SECOND:
				m_timerMS = m_interval*1000;
				break;
			case TIME_UNIT_MINUTE:
				m_timerMS = m_interval*60*1000;
				break;
			case TIME_UNIT_HOUR:
				m_timerMS = m_interval*60*60*1000;
				break;
			case TIME_UNIT_DAY:
				m_timerMS = m_interval*24*60*60*1000;
				break;
			default:
				return STATUS_ERROR;
		}
	}
	m_isExpired = false;
	return STATUS_OK;
}
/*定时器定时响应 */
void Timer::onTick(EventCenter* eventCenter)
{
	if(m_isExpired)
	{
		return;
	}
	if(m_isAbsTimer)
	{
		RtcTime_S currTime;
		RtcFacade::getInstance()->readTime(currTime);
		if ((currTime.m_hour == m_absTime.m_hour) &&
			(currTime.m_minute == m_absTime.m_minute) &&
			(currTime.m_second == m_absTime.m_second))
		{
			onTimer(eventCenter);
			m_isExpired = true;
			if(TIMER_TYPE_PERIODIC==m_type)
			{
				reset();
			}
		}
	}
	else
	{
		m_timerMS -= TIMER_TICK_MS;
		if(m_timerMS <= 0 )
		{
			onTimer(eventCenter);
			m_isExpired = true;
			if(TIMER_TYPE_PERIODIC==m_type)
			{
				reset();
			}
		}
	}
}

PeriodicTimer::PeriodicTimer(RtcTime_S absTime, int event)
:Timer(absTime)
{
	m_event=event;
	m_type=TIMER_TYPE_PERIODIC;
}
PeriodicTimer::PeriodicTimer(int interval, int unit, int event)
:Timer(interval,unit)
{
	m_event=event;
	m_type=TIMER_TYPE_PERIODIC;
}

PeriodicTimer::~PeriodicTimer()
{
}

void PeriodicTimer::onTimer(EventCenter* eventCenter)
{
	Event evt(m_event);
	eventCenter->postEvent(evt);
}

OneShotTimer::OneShotTimer(RtcTime_S absTime, int event)
:Timer(absTime)
{
	m_event=event;
	m_type=TIMER_TYPE_ONESHOT;
}
OneShotTimer::OneShotTimer(int interval, int unit, int event)
:Timer(interval,unit)
{
	m_event=event;
	m_type=TIMER_TYPE_ONESHOT;
}

OneShotTimer::~OneShotTimer()
{
}

void OneShotTimer::onTimer(EventCenter* eventCenter)
{
	Event evt(m_event);
	eventCenter->postEvent(evt);
}

TimerManager::TimerManager()
{
	m_timerThread.start(this);
}

TimerManager::~TimerManager()
{
	m_timerThread.cancel();
}

/**
 *  \brief  增加定时器
 *  \param  timer 定时器
 *  \return 成功返回STATUS_OK,失败返回STATUS_ERROR
 *  \note   none
 */
int TimerManager::addTimer(Timer* timer)
{
	AutoLock lock(&m_listLock);
	std::list<Timer*>::iterator iter;
	for(iter=m_timerList.begin(); iter!=m_timerList.end(); iter++)
	{
		if((*iter) == timer)
		{
			(*iter)->reset();
			return STATUS_OK;
		}
	}
	timer->reset();
	m_timerList.push_back(timer);
	return STATUS_OK;
}

/**
 *  \brief  移除定时器
 *  \param  timer 定时器
 *  \return 成功返回STATUS_OK,失败返回STATUS_ERROR
 *  \note   none
 */
int TimerManager::removeTimer(Timer* timer)
{
	AutoLock lock(&m_listLock);
	std::list<Timer*>::iterator iter;
	for(iter=m_timerList.begin(); iter!=m_timerList.end(); iter++)
	{
		if((*iter) == timer)
		{
			m_timerList.erase(iter);
			return STATUS_OK;
		}
	}
	return STATUS_OK;
}

/**
 *  \brief  重新启用定时器
 *  \param  timer 定时器
 *  \return 成功返回STATUS_OK,失败返回STATUS_ERROR
 *  \note   none
 */
int TimerManager::restartTimer(Timer* timer)
{
	AutoLock lock(&m_listLock);
	std::list<Timer*>::iterator iter;
	for(iter=m_timerList.begin(); iter!=m_timerList.end(); iter++)
	{
		if((*iter) == timer)
		{
			timer->reset();
			return STATUS_OK;
		}
	}
	return STATUS_OK;
}


/* 定时器管理者线程 */
void TimerManager::run()
{
	std::list<Timer*>::iterator iter;
	while(1)
	{
		Thread::msleep(TIMER_TICK_MS);
		m_listLock.lock();
		for(iter=m_timerList.begin(); iter!=m_timerList.end(); iter++)
		{
			(*iter)->onTick(this);
		}
		m_listLock.unLock();
	}
}

/**
 *  \brief  默认CTimer定时器回调
 *  \param  timerId 定时器id
 *  \return none
 *  \note   使用统一定时器回调函数时,定时器使用者应自行实现此函数.
 */
void CTimerProtocol::onCTimer(int timerId)
{
    TRACE_ERR_CLASS("not implement timer(%d) action!\n",timerId);
}

CTimer::CTimer(int id, CTimerProtocol*owner):
m_timerId(id),
m_startFlag(false),
m_owner(owner)
{
}

CTimer::~CTimer()
{
}
/**
 *  \brief  启用定时器
 *  \param  interval 时间间隔
 *  \param  unit 时间单位
 *  \param  ontimer 定时回调函数,如果不设置则使用统一默认的onCTimer函数.
 *  \return 成功返回STATUS_OK,失败返回STATUS_ERROR
 *  \note   定时时间最小为100ms
 */
int CTimer::start(int interval, int unit, SEL_onctimer onctimer)
{
    if (m_startFlag || interval<=0)
    {
        return STATUS_ERROR;
    }
    switch(unit)
	{
		case TIME_UNIT_MILLISECOND:
			m_timerMS = interval;
			break;
		case TIME_UNIT_SECOND:
			m_timerMS = interval*1000;
			break;
		case TIME_UNIT_MINUTE:
			m_timerMS = interval*60*1000;
			break;
		case TIME_UNIT_HOUR:
			m_timerMS = interval*60*60*1000;
			break;
		case TIME_UNIT_DAY:
			m_timerMS = interval*24*60*60*1000;
			break;
		default:
			return STATUS_ERROR;
	}
    if (m_timerMS<100)
    {
        return STATUS_ERROR;
    }
    m_timeLeft = m_timerMS;
    m_startFlag = true;
    m_ontime = onctimer;
    m_mainThread.start(this);
    return STATUS_OK;
}
/**
 *  \brief  停止定时器
 *  \param  none
 *  \return 成功返回STATUS_OK,失败返回STATUS_ERROR
 *  \note   none
 */
int CTimer::stop()
{
    m_startFlag = false;
    return STATUS_OK;
}

void CTimer::run()
{
    while(1)
    {
        if (m_startFlag)
        {
            Thread::msleep(100);
            m_timeLeft -= 100;
            if (m_timeLeft<=0)
            {
                if (m_ontime==NULL)
                {
                    m_owner->onCTimer(m_timerId);
                }
                else
                {
                    (m_owner->*(m_ontime))();
                }
                m_timeLeft = m_timerMS;
            }
        }
        else
        {
            break;
        }
    }
}